package matrix;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class SquareMatrix<T1, T2>
{	
	protected ArrayList<ArrayList<T2>> matrix;

	protected boolean isMirror;
	protected ArrayList<T1> keys;
	protected int size;
		
	public SquareMatrix(Collection<T1> values, boolean isMirror)
	{
		this.isMirror = isMirror;
		this.size = values.size();
		this.matrix = new ArrayList<ArrayList<T2>>();
		
		this.keys =  new ArrayList<T1>();
		
		for(Iterator<T1> itValues = values.iterator(); itValues.hasNext(); )
		{
			T1 value = itValues.next();
			keys.add(value);
		}
		
		
		for(int row = 0; row < this.size; row++)
		{
			this.matrix.add(new ArrayList<T2>());
			for(int col = 0; col < this.size; col++)
			{
				this.matrix.get(row).add(this.getNeutralValue());
			}
		}
	}
	
	public SquareMatrix(boolean isMirror)
	{
		this.isMirror = isMirror;
		this.size = 0;
		this.matrix = new ArrayList<ArrayList<T2>>();
		
		this.keys =  new ArrayList<T1>();
	}
	
	public SquareMatrix(Collection<T1> values, T2 initialValue, boolean isMirror)
	{
		this.isMirror = isMirror;
		this.size = values.size();
		this.matrix = new ArrayList<ArrayList<T2>>();
		
		this.keys =  new ArrayList<T1>();
		
		for(Iterator<T1> itValues = values.iterator(); itValues.hasNext(); )
		{
			T1 value = itValues.next();
			keys.add(value);
		}
		
		for(int row = 0; row < this.size; row++)
		{
			this.matrix.add(new ArrayList<T2>());
			for(int col = 0; col < this.size; col++)
			{
				this.matrix.get(row).add(initialValue);
			}
		}
	}
	
	public SquareMatrix(Collection<T1> values)
	{
		this(values, false);
	}
	
	public int getSize()
	{
		return this.size;
	}
	
	public void set(int row, int col, T2 value)
	{
		this.matrix.get(row).set(col,value);
		if(this.isMirror)
		{
			this.matrix.get(col).set(row,value);
		}
	}
	
	public T2 get(int row, int col)
	{
		return this.matrix.get(row).get(col);
	}
	
	public void set(T1 row, T1 col, T2 value)
	{
		int rowIndex = this.getIndex(row);
		int colIndex = this.getIndex(col);
		this.set(rowIndex, colIndex, value);
	}
	
	public T2 get(T1 row, T1 col)
	{
		int rowIndex = this.getIndex(row);
		int colIndex = this.getIndex(col);
		
		return this.get(rowIndex, colIndex);
	}
	
	public void addKey(T1 key)
	{
		this.keys.add(key);
		this.size++;
		
		for(int row = 0; row < this.size; row++)
		{
			
			if(row == this.size -1)
			{
				this.matrix.add(new ArrayList<T2>());
				for(int col = 0; col < this.size; col++)
				{
					this.matrix.get(row).add(this.getNeutralValue());
				}
			}
			else
			{
				this.matrix.get(row).add(this.getNeutralValue());
			}
		}
	}
	
	private T2 getNeutralValue()
	{
		return null;
	}
	

	protected int getIndex(T1 value)
	{
		int i = 0;
		for(Iterator<T1> it = keys.iterator(); it.hasNext();)
		{
			T1 currentValue = it.next();
			if(currentValue == value)
			{
				return i;
			}
			i++;
		}
		return -1;
	}
	
	public String toString()
	{
		String returnString = "      ";
		
		for(Iterator<T1> it = this.keys.iterator(); it.hasNext();)
		{
			returnString += " |  " +  it.next();
		}
		
		returnString += "\n";
		
		for(int row = 0; row < this.size; row++)
		{	
			returnString += this.keys.get(row);
			
			for(int col = 0; col < this.size; col++)
			{
				returnString += "   |   " +  this.get(row, col);
			}	
			returnString += "\n";
		}
		return returnString;
	}
	
	public ArrayList<T1> getKeys()
	{
		return this.keys;
	}
	
	public ArrayList<String> getKeysString()
	{
		ArrayList<String> strs = new ArrayList<String>();
		strs.addAll(strs);
		return strs;
	}
	
	public String[] getKeysArrayString()
	{
		String[] strs = new String[this.size];
		int i = 0;
		for(Iterator<T1> it = this.keys.iterator(); it.hasNext();)
		{
			strs[i++] = it.next().toString();
		}
		return strs;
	}
}
